package org.meb.lotrlcg.web.ctrl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ResourceBundle;

import javax.annotation.PostConstruct;
import javax.enterprise.event.Observes;
import javax.faces.context.FacesContext;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;

import lombok.Getter;
import lombok.Setter;

import org.apache.commons.lang.StringUtils;
import org.meb.lotrlcg.db.dao.Query;
import org.meb.lotrlcg.db.dao.Query.Mode;
import org.meb.lotrlcg.db.model.Card;
import org.meb.lotrlcg.db.model.CardSet;
import org.meb.lotrlcg.db.model.Domain;
import org.meb.lotrlcg.db.model.EncounterSet;
import org.meb.lotrlcg.web.AutoCompleteCache;
import org.meb.lotrlcg.web.AutoCompleteItem;
import org.meb.lotrlcg.web.event.LanguageChangeEvent;
import org.meb.lotrlcg.web.services.SearchService;
import org.meb.lotrlcg.web.services.User;
import org.primefaces.model.DefaultTreeNode;
import org.primefaces.model.TreeNode;

@Named
@ViewScoped
@Getter
@Setter
public class CopyOfCardSearchCtrl implements Serializable {

	private static final long serialVersionUID = 3973801993975443027L;

	private boolean searchFiltersCollapsed;
	private List<Card> cards;
	private Card selectedCard;

	@Inject
	private User user;

	@Inject
	private SearchService searchService;

	@Inject
	private EntityManager em;
	
	@Inject
	private AutoCompleteCache autoCompleteCache;

	private TreeNode root;
	private TreeNode[] selectedNodes;

	private DefaultTreeNode sphereRoot;
	private TreeNode[] sphereSelectedNodes;

	private DefaultTreeNode encounterSetRoot;
	private TreeNode[] encounterSetSelectedNodes;

	private LinkedHashMap<String, String> sphereItems;
	private List<String> selectedSpheres;

	private ArrayList<AutoCompleteItem> cardSetItems;

	private CardSet selectedCardSet;
	private List<CardSet> selectedCardSets;

	private List<EncounterSet> selectedEncounterSets;

	@PostConstruct
	public void initialize() {
		prepareFilterTrees();
	}

	private void prepareFilterTrees() {
		prepareSphereTree();
		prepareCardSetTree();
		prepareEncounterSetTree();
	}

	private void prepareSphereTree() {
		ResourceBundle bundle = getResourceBundle();

		sphereRoot = new DefaultTreeNode();
		TreeNode all = new DefaultTreeNode(bundle.getString("sphere"), sphereRoot);
		all.setExpanded(true);

		sphereItems = new LinkedHashMap<String, String>();
		selectedSpheres = new ArrayList<String>();
		List<Domain> domains = searchService.find(new Domain("SPHERE"));
		for (Domain domain : domains) {
			new DefaultTreeNode(domain.getDescription(), all);
			sphereItems.put(domain.getDescription(), domain.getValue());
			selectedSpheres.add(domain.getValue());
		}
	}

	private void prepareCardSetTree() {
		ResourceBundle bundle = getResourceBundle();

		root = new DefaultTreeNode();
		TreeNode all = new DefaultTreeNode(bundle.getString("cardSet"), root);
		all.setExpanded(true);

		String cycleCode = null;
		TreeNode cycleNode = null;

		List<CardSet> cardSets = searchService.find(new CardSet());
		for (CardSet cardSet : cardSets) {
			if (StringUtils.isBlank(cardSet.getCycleCode())) {
				cycleCode = null;
				cycleNode = null;
				new DefaultTreeNode(cardSet.getName(), all);
			} else {
				if (!cardSet.getCycleCode().equals(cycleCode)) {
					// add cycle to root
					cycleCode = cardSet.getCycleCode();
					cycleNode = new DefaultTreeNode("inner", cardSet.getCycleName(), all);
				}
				// add set to cycle
				new DefaultTreeNode(cardSet.getName(), cycleNode);
			}
		}
	}

	private void prepareEncounterSetTree() {
		ResourceBundle bundle = getResourceBundle();

		encounterSetRoot = new DefaultTreeNode();
		TreeNode all = new DefaultTreeNode(bundle.getString("encounterSet"), encounterSetRoot);
		all.setExpanded(true);

		Long crstId = null;
		TreeNode crstNode = null;

		List<EncounterSet> encounterSets = searchService.find(new EncounterSet());
		for (EncounterSet encounterSet : encounterSets) {
			if (encounterSet.getCrstId() == null) {
				crstId = null;
				crstNode = null;
				new DefaultTreeNode(encounterSet.getName(), all);
			} else {
				if (!encounterSet.getCrstId().equals(crstId)) {
					// add cycle to root
					crstId = encounterSet.getCrstId();
					crstNode = new DefaultTreeNode(encounterSet.getCrstName(), all);
				}
				// add set to cycle
				new DefaultTreeNode(encounterSet.getName(), crstNode);
			}
		}
	}

	private ResourceBundle getResourceBundle() {
		FacesContext ctx = FacesContext.getCurrentInstance();
		ResourceBundle bundle = ctx.getApplication().getResourceBundle(ctx, "msgs");
		return bundle;
	}

	public List<Card> completeCard(String query) {
		Card example = new Card();
		example.setName(query + "%");
		return searchService.find(example);
	}

	@SuppressWarnings("unused")
	private void languageChangeEventHandler(@Observes LanguageChangeEvent event) {
		prepareFilterTrees();
	}

	public void search() {
		System.out.println();
	}

	public List<CardSet> completeCardSet(String value) {
		String likeValue = "%" + value + "%";

		CardSet example = new CardSet();
		example.setName(likeValue);
		example.setCycleName(likeValue);
		List<CardSet> results = searchService.find(new Query<CardSet>(example, Mode.OR));
		for (CardSet result : results) {
			autoCompleteCache.add(AutoCompleteItem.create(result));
			result.setName(markText(result.getName(), value));
			result.setCycleName(markText(result.getCycleName(), value));
		}
		return results;
	}

	public List<EncounterSet> completeEncounterSet(String value) {
		String likeValue = "%" + value + "%";

		EncounterSet example = new EncounterSet();
		example.setName(likeValue);
		example.setCrstName(likeValue);
		example.setCycleName(likeValue);
		List<EncounterSet> results = searchService.find(new Query<EncounterSet>(example, Mode.OR));
		for (EncounterSet result : results) {
			autoCompleteCache.add(AutoCompleteItem.create(result));
			result.setName(markText(result.getName(), value));
			result.setCrstName(markText(result.getCrstName(), value));
			result.setCycleName(markText(result.getCycleName(), value));
		}
		return results;
	}

	private String markText(String text, String search) {
		int beginIdx = StringUtils.indexOfIgnoreCase(text, search);
		if (beginIdx != -1) {
			int endIdx = beginIdx + search.length();
			text = text.substring(0, beginIdx) + "<span class=\"autocomplete-text-match\">"
					+ text.substring(beginIdx, endIdx) + "</span>" + text.substring(endIdx);
		}
		return text;
	}
}